Add in-process FFI transport for Rust SDK#1915
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
9587efd to
259911f
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Generated by SDK Consistency Review Agent for issue #1915 · sonnet46 2M
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Generated by SDK Consistency Review Agent for issue #1915 · sonnet46 2.4M
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Generated by SDK Consistency Review Agent for issue #1915 · sonnet46 2M
Comments that could not be inline-anchored
nodejs/src/client.ts:639
Cross-SDK consistency: missing eager validation for inprocess + incompatible options
The .NET SDK (reference implementation since #1901) throws an ArgumentException in the constructor when Environment or Telemetry options are set alongside InProcessRuntimeConnection — see Client.cs ValidateEnvironmentOptions(). The new TypeScript implementation only documents the limitation in JSDoc but silently ignores those options, which can be confusing.
Suggest adding a "fail fast" chec…
rust/src/lib.rs:1012
Cross-SDK consistency: missing eager validation for Transport::InProcess + incompatible options
The .NET SDK (reference since #1901) rejects incompatible options early with ArgumentException. The TypeScript implementation (also added in this PR) has the same gap. For Rust, suggest adding a validation block after the External checks, mirroring the pattern here:
if matches!(options.transport, Transport::InProcess) {
if options.github_token.is_some() {
return Err(Er…
</details>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
6b989d4 to
b1576e0
Compare
Cross-SDK Consistency ReviewThis PR ports the in-process FFI transport from .NET (#1901) to TypeScript and Rust. Here's how the implementations compare. ✅ API naming — consistent across the three SDKs
|
There was a problem hiding this comment.
Generated by SDK Consistency Review Agent for issue #1915 · sonnet46 2M
b1576e0 to
cc686bb
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
441f78c to
4d480b4
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
There was a problem hiding this comment.
Pull request overview
Adds an in-process (FFI) transport option to the Rust SDK so it can host the Copilot runtime cdylib directly (no CLI subprocess), while updating bundling/pinning to include the native runtime library and expanding CI/E2E coverage for the new transport.
Changes:
- Introduces
Transport::{Default, Stdio{env}, InProcess, Tcp{env}, External}and updatesClient::start/option validation to support env-driven default transport selection and in-process hosting behindbundled-in-process. - Adds a Rust FFI host (
rust/src/ffi.rs) that loads/binds the runtime library once per process and bridges the runtime connection toAsyncRead/AsyncWrite. - Updates Rust E2E harness/tests, docs, build/publish scripts, and CI workflows to exercise in-process mode and to bundle/verify the runtime library alongside the embedded CLI.
Show a summary per file
| File | Description |
|---|---|
| rust/tests/integration_test.rs | Updates test options to reflect working_directory: Option<PathBuf> API change. |
| rust/tests/e2e/telemetry.rs | Skips telemetry test under in-process transport due to per-client env limitations. |
| rust/tests/e2e/support.rs | Adds in-process env mirroring guard, default user setup, in-process client starter, and serializes E2E concurrency for in-process runs. |
| rust/tests/e2e/subagent_hooks.rs | Skips sub-agent hook test in-process due to process-global inference provider limitations. |
| rust/tests/e2e/session_config.rs | Skips specific in-process-incompatible scenario; updates TCP transport struct usage. |
| rust/tests/e2e/rpc_workspace_checkpoints.rs | Skips in-process case where native checkpoint decoding rejects the test sentinel. |
| rust/tests/e2e/rpc_session_state_extras.rs | Switches to helper that applies GitHub token appropriately for in-process. |
| rust/tests/e2e/rpc_server.rs | Switches to helper that applies GitHub token appropriately for in-process. |
| rust/tests/e2e/provider_endpoint.rs | Adjusts env gating behavior for in-process and updates token configuration helper usage. |
| rust/tests/e2e/per_session_auth.rs | Skips in-process scenarios that depend on unsupported client-level tokens; adjusts unauthenticated case. |
| rust/tests/e2e/pending_work_resume.rs | Updates TCP transport struct usage. |
| rust/tests/e2e/multi_client.rs | Updates TCP transport struct usage. |
| rust/tests/e2e/multi_client_commands_elicitation.rs | Updates TCP transport struct usage. |
| rust/tests/e2e/inprocess.rs | Adds a basic in-process E2E smoke test (ping/status/stop). |
| rust/tests/e2e/copilot_request_handler.rs | Skips handler-driven tests in-process due to process-global provider slot semantics. |
| rust/tests/e2e/client.rs | Updates TCP transport struct usage and token configuration helper usage. |
| rust/tests/e2e/client_options.rs | Updates transport usage to new Stdio { env: None } form. |
| rust/tests/e2e/byok_bearer_token_provider.rs | Skips BYOK provider tests in-process to avoid poisoning process-global runtime state. |
| rust/tests/e2e.rs | Registers the new in-process test module behind bundled-in-process. |
| rust/tests/cli_resolution_test.rs | Extends pin-file validation for in-process snapshot format and asserts runtime library install when bundled-in-process. |
| rust/src/lib.rs | Adds transport variants, option validation, transport env replacement support, and in-process client startup/teardown wiring. |
| rust/src/ffi.rs | New Rust FFI runtime host/transport implementation using libloading and async stream adapters. |
| rust/src/embeddedcli.rs | Extends embedded CLI installation to also extract/install the native runtime library when bundled-in-process is enabled. |
| rust/scripts/snapshot-bundled-in-process-version.sh | Adds script to snapshot npm integrity pins for platform packages used by bundled-in-process builds. |
| rust/README.md | Updates Rust SDK docs for transport changes and new bundled-in-process feature. |
| rust/Cargo.toml | Adds bundled-in-process feature, includes build module sources in crate packaging, and adds libloading dependency. |
| rust/Cargo.lock | Records libloading dependency addition. |
| rust/build/out_of_process.rs | Refactors legacy build logic into module used when bundled-in-process is off. |
| rust/build/in_process.rs | Adds build logic to download/verify npm package tgz and embed minimal archive with optional runtime library. |
| rust/build.rs | Switches to selecting build implementation module based on bundled-in-process feature. |
| rust/.gitignore | Ignores generated cli-version-in-process.txt. |
| .github/workflows/rust-sdk-tests.yml | Adds in-process Rust E2E job (Linux/macOS), updates cache naming and clippy features. |
| .github/workflows/publish.yml | Snapshots and verifies both CLI pin files during publish. |
| .github/lsp.json | Removes rust-analyzer configuration from the repo LSP mapping. |
Review details
- Files reviewed: 33/34 changed files
- Comments generated: 3
- Review effort level: Low
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: da0a9335-969e-4a77-838a-daac9206a454
Reverts the source-breaking API changes the in-process transport work
introduced for existing Stdio/Tcp consumers:
- Restore `Transport::Stdio` as a unit variant and `Transport::Tcp` to
`{ port, connection_token }` (drop the per-transport `env` field). Env
stays on `ClientOptions::env`/`env_remove`, which still applies to the
child process and is already rejected for `Transport::InProcess`.
- Restore `ClientOptions::working_directory` to `PathBuf` (empty = unset,
resolved to the process cwd at start). The InProcess guard now rejects a
non-empty working_directory.
- Un-deprecate `env`/`env_remove`/`with_env`/`with_env_remove` (their notes
pointed at the removed transport-level env).
`Transport::Default`, `Transport::InProcess`, and COPILOT_SDK_DEFAULT_CONNECTION
are additive and unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 95ad333b-ef14-474c-9908-75ed3e21e06f
Summary
Adds an in-process transport to the Rust SDK so it can host the Copilot runtime cdylib directly instead of spawning a CLI subprocess. The transport continues to use the existing LSP-framed JSON-RPC connection over the runtime C ABI.
Changes
Transport::InProcessand supports selecting it withCOPILOT_SDK_DEFAULT_CONNECTION=inprocess.AsyncRead/AsyncWritestreams.runtime.nodelibrary alongside the embedded CLI, including platform-specific library naming.Backward compatibility
The existing out-of-process (stdio/tcp) transports remain source-compatible — no breaking changes for current consumers:
Transport::Stdiostays a unit variant andTransport::Tcpkeeps{ port, connection_token }(no per-transportenvfield).ClientOptions::working_directorystaysPathBuf(an empty path means "unset" and resolves to the process cwd atstart()).ClientOptions::env/env_remove(andwith_env/with_env_remove) remain non-deprecated; they still apply to the child process for stdio/tcp and are rejected forTransport::InProcess.Transport::Default,Transport::InProcess, andCOPILOT_SDK_DEFAULT_CONNECTIONare additive.Scope
This PR now contains only Rust SDK changes plus the Rust SDK test workflow. The TypeScript/Node implementation was removed because it merged separately.